package com.zhala.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.github.pagehelper.PageInfo;
import com.zhala.common.core.domain.CommonResult;
import com.zhala.common.core.domain.PageResult;
import com.zhala.common.utils.DateUtils;
import com.zhala.common.utils.uuid.IdUtils;
import com.zhala.system.config.MaterialConfig;
import com.zhala.system.config.MaterialItem;
import com.zhala.system.domain.ZlSteelPlate;
import com.zhala.system.domain.vo.*;
import com.zhala.system.mapper.ZlSteelPlateMapper;
import com.zhala.system.service.CommonService;
import com.zhala.system.service.ISysConfigService;
import com.zhala.system.service.IZlSteelPlateService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.SimpleDateFormat;
import java.util.*;

import static com.zhala.common.utils.PageUtils.startPage;

/**
 * 钢板信息Service业务层处理
 *
 * @author ruoyi
 * @date 2024-11-11
 */
@Service
public class ZlSteelPlateServiceImpl implements IZlSteelPlateService {
    @Autowired
    private ZlSteelPlateMapper zlSteelPlateMapper;
    @Autowired
    private CommonService commonService;
    @Autowired
    private MaterialConfig config;
    @Autowired
    private ISysConfigService configService;

    /**
     * 查询钢板信息
     *
     * @param ID 钢板信息主键
     * @return 钢板信息
     */
    @Override
    public ZlSteelPlate selectZlSteelPlateByID(String ID) {
        return zlSteelPlateMapper.selectZlSteelPlateByID(ID);
    }

    /**
     * 查询钢板信息列表
     *
     * @param zlSteelPlate 钢板信息
     * @return 钢板信息
     */
    @Override
    public List<ZlSteelPlate> selectZlSteelPlateList(ZlSteelPlate zlSteelPlate) {
        return zlSteelPlateMapper.selectZlSteelPlateList(zlSteelPlate);
    }


    /**
     * 新增钢板信息
     *
     * @param zlSteelPlate 钢板信息
     * @return 结果
     */
    @Override
    public int insertZlSteelPlate(ZlSteelPlate zlSteelPlate) {
        zlSteelPlate.setCreateTime(DateUtils.getNowDate());
        return zlSteelPlateMapper.insertZlSteelPlate(zlSteelPlate);
    }

    /**
     * 修改钢板信息
     *
     * @param zlSteelPlate 钢板信息
     * @return 结果
     */
    @Override
    public int updateZlSteelPlate(ZlSteelPlate zlSteelPlate) {
        zlSteelPlate.setUpdateTime(DateUtils.getNowDate());
        return zlSteelPlateMapper.updateZlSteelPlate(zlSteelPlate);
    }

    /**
     * 批量删除钢板信息
     *
     * @param IDs 需要删除的钢板信息主键
     * @return 结果
     */
    @Override
    public int deleteZlSteelPlateByIDs(String[] IDs) {
        return zlSteelPlateMapper.deleteZlSteelPlateByIDs(IDs);
    }

    /**
     * 删除钢板信息信息
     *
     * @param ID 钢板信息主键
     * @return 结果
     */
    @Override
    public CommonResult<Boolean> deleteZlSteelPlateByID(String ID) {
        ZlSteelPlate zlSteelPlate = zlSteelPlateMapper.selectZlSteelPlateByID(ID);
        if(zlSteelPlate!=null && StringUtils.isNotBlank(zlSteelPlate.getPipeId())){
            return  CommonResult.error("当前钢板已使用，无法删除！");
        }
        zlSteelPlateMapper.deleteZlSteelPlateByID(ID);
        return CommonResult.success(true);
    }


    /**
     * 接受钢板信息并录入系统
     * <p>
     * 该方法将用户提供的钢板验收请求信息转换为系统内部的钢板对象，并将其保存到数据库中
     * 使用了对象属性拷贝、唯一标识生成和当前日期获取等工具方法，以简化数据处理过程
     *
     * @param reqVO 用户提交的钢板验收请求对象，包含需要录入系统的钢板信息
     * @return 返回一个通用结果对象，表示操作是否成功
     */
    @Override
    public CommonResult<Boolean> acceptance(SteelPlateAcceptanceReqVO reqVO) {
        // 创建一个新的ZlSteelPlate对象，用于存储钢板信息
        ZlSteelPlate ZlSteelPlate = new ZlSteelPlate();
        // 使用BeanUtils工具类将请求对象的属性值拷贝到ZlSteelPlate对象中
        BeanUtils.copyProperties(reqVO, ZlSteelPlate);
        ZlSteelPlate zlSteelPlate = zlSteelPlateMapper.getByBatchNumAndSerialNum(ZlSteelPlate.getBatchNum(), ZlSteelPlate.getSerialNum());
        if (zlSteelPlate != null) {
            return CommonResult.error("该已存在相同批号和序列号的钢板信息,请检查批号和序列号是否正确！");
        }
        // 为ZlSteelPlate对象设置唯一的标识符
        ZlSteelPlate.setId(IdUtils.fastUUID());
        // 设置删除标记为false，表示该记录未被删除
        ZlSteelPlate.setDeleted(false);
        String materialAlias = this.getMaterialAlias(reqVO.getMaterial());
        if (StringUtils.isBlank(materialAlias)) {
            return CommonResult.error("该材质别名不存在，请检查输入是否正确！");
        }
        ZlSteelPlate.setMaterial(reqVO.getMaterial());
        ZlSteelPlate.setMaterialAlias(materialAlias);
        commonService.initPojo(ZlSteelPlate);
        // 调用Mapper方法将ZlSteelPlate对象插入到数据库中
        zlSteelPlateMapper.insertZlSteelPlate(ZlSteelPlate);
        // 返回操作成功的结果
        return CommonResult.success(true);
    }


    /**
     * 根据条件分页查询钢板信息
     *
     * @param reqVO 钢板分页查询请求对象，包含查询条件和分页参数
     * @return 返回分页结果对象，包含总记录数和钢板列表
     */
    @Override
    public PageResult<List<ZlSteelPlate>> page(SteelPlatePageReqVO reqVO) {
        // 根据请求的页码和页大小启动分页查询
        startPage(reqVO.getPageNo(), reqVO.getPageSize());
        // 获取月份开始日期，如果请求中包含月份信息
        Date monthStartDate = reqVO.getMonth() != null ? DateUtils.getMonthStartDate(reqVO.getMonth()) : null;
        // 获取月份结束日期，如果请求中包含月份信息
        Date monthEndDate = reqVO.getMonth() != null ? DateUtils.getMonthEndDate(reqVO.getMonth()) : null;
        // 调用Mapper方法，根据日期范围和批次号查询钢板列表
        List<ZlSteelPlate> list = zlSteelPlateMapper.pageList(monthStartDate, monthEndDate, reqVO.getBatchNum(), null, null);
        // 创建分页结果对象
        PageResult result = new PageResult();
        // 设置总记录数，通过PageInfo对象获取
        result.setTotal(new PageInfo(list).getTotal());
        // 设置查询到的钢板列表
        result.setList(list);
        // 返回分页结果
        return result;
    }

    /**
     * 根据类型获取钢板列表
     * 此方法用于处理获取不同类型钢板列表的请求它首先规范化类型参数，
     * 然后调用mapper方法获取相应的钢板列表
     *
     * @return 返回一个包含钢板列表的CommonResult对象，表示查询结果
     */
    @Override
    public CommonResult<List<ZlSteelPlate>> list(PlateListReqVO reqVO) {
        // 规范化类型参数，如果为null或0，则设置为null，以便于后续查询
        Integer type = reqVO.getType() == null || reqVO.getType() == 0 ? null : reqVO.getType();
        // 调用mapper方法，获取相应类型的钢板列表
        List<ZlSteelPlate> list = zlSteelPlateMapper.pageList(null, null, null, type, reqVO.getMaterial());
        // 返回包含查询结果的CommonResult对象
        return CommonResult.success(list);
    }

    /**
     * 统计钢板信息
     * 该方法根据当前日期获取当月的开始和结束时间，并调用mapper层进行数据统计
     * 主要用于统计当前月份的钢板使用情况
     *
     * @return 返回一个CommonResult对象，其中包含统计结果列表
     */
    @Override
    public CommonResult<List<PlateStatisticsRespVO>> statistics(StatisticsReqVO reqVO) {
        List<PlateStatisticsRespVO> result = new ArrayList<>();
        // 获取当前日期
        Date now = reqVO.getMonth() == null ? DateUtils.getNowDate() : reqVO.getMonth();
        // 计算当月的开始时间
        Date monthStartTime = DateUtils.getMonthStartDate(now);
        // 计算当月的结束时间
        Date monthEndTime = DateUtils.getMonthEndDate(now);
        // 调用mapper层方法，统计当月的钢板信息
        List<PlateStatisticsRespVO> list = zlSteelPlateMapper.statistics(monthStartTime, monthEndTime);
        // 遍历材料列表，匹配统计结果
        for (MaterialItem material : config.getMaterials()) {
            result.add(this.matchStatistics(list, material.getMaterial()));
        }
        // 返回统计结果
        return CommonResult.success(result);
    }


    /**
     * 获取所有钢板材料信息
     * <p>
     * 此方法返回一个包含所有supportedMaterials的CommonResult对象
     * 主要用于获取系统中支持的所有素材项列表，可以用于展示或进一步处理
     *
     * @return CommonResult<List < MaterialItem>> 包含所有supportedMaterials的CommonResult对象
     */
    @Override
    public CommonResult<List<MaterialItem>> materials() {
        // 返回包含所有supportedMaterials的CommonResult对象
        return CommonResult.success(config.getMaterials());
    }

    /**
     * 获取批次号列表
     * <p>
     * 该方法用于获取所有批次号的列表，以便进行进一步的处理或展示
     * 它调用了zlSteelPlateMapper中的lstBatchNums方法来实现数据的获取
     *
     * @return 包含批次号列表的CommonResult对象
     */
    @Override
    public CommonResult<List<String>> listBatchNums() {
        return CommonResult.success(zlSteelPlateMapper.lstBatchNums());
    }

    /**
     * 根据ID获取钢板的详细信息
     *
     * @param id 钢板的唯一标识符
     * @return 包含钢板信息的通用结果对象
     */
    @Override
    public CommonResult<ZlSteelPlate> detail(String id) {
        // 通过ID从数据库中查询钢板信息
        ZlSteelPlate zlSteelPlate = zlSteelPlateMapper.selectZlSteelPlateByID(id);
        // 返回成功结果，包含查询到的钢板信息
        return CommonResult.success(zlSteelPlate);
    }

    /**
     * 获取安装位置信息
     * <p>
     * 本方法通过从配置服务中获取安装位置的配置信息，并将其解析为列表形式返回
     * 主要用于需要获取系统或者应用安装位置的场景
     *
     * @return CommonResult<List < Map>> 返回一个通用结果对象，包含解析后的安装位置列表
     */
    @Override
    public CommonResult<List<Map>> getInstallLocation() {
        // 根据键名"install_location"从配置服务中获取配置信息
        String config = configService.selectConfigByKey("install_location");
        // 将获取的配置信息解析为Map对象的列表
        List<Map> list = JSON.parseArray(config, Map.class);
        // 返回包含解析后列表的通用结果对象
        return CommonResult.success(list);
    }

    /**
     * 根据给定的物料号匹配并更新统计信息
     * 如果列表为空，创建并返回一个新的统计信息对象，总数量为0
     * 如果列表不为空，遍历列表寻找匹配的物料号，更新其统计信息
     * 如果找到匹配项，更新其总数量、已使用数量和未使用数量
     * 如果未找到匹配项，创建并返回一个新的统计信息对象，总数量为0
     *
     * @param list     统计信息列表
     * @param material 物料号
     * @return 匹配并更新后的统计信息对象
     */
    private PlateStatisticsRespVO matchStatistics(List<PlateStatisticsRespVO> list, String material) {
        // 判断列表是否为空
        if (CollectionUtils.isEmpty(list)) {
            // 如果列表为空，创建新的统计信息对象，设置物料号和总数量为0
            PlateStatisticsRespVO me = new PlateStatisticsRespVO();
            me.setMaterial(material);
            me.setTotal(0);
            return me;
        }
        // 遍历列表，寻找匹配的物料号
        for (PlateStatisticsRespVO item : list) {
            // 如果找到匹配的物料号，更新其统计信息
            if (material.equals(item.getMaterial())) {
                item.setTotal(item.getTotal() == null ? 0 : item.getTotal());
                item.setUsed(item.getUnUse() == null ? 0 : item.getUnUse());
                item.setUnUse(item.getUsed() == null ? 0 : item.getUsed());
                return item;
            }
        }
        // 如果列表不为空但未找到匹配的物料号，创建新的统计信息对象，设置物料号和总数量为0
        PlateStatisticsRespVO me = new PlateStatisticsRespVO();
        me.setMaterial(material);
        me.setTotal(0);
        return me;
    }


    /**
     * 根据材料名称获取其别名
     * 此方法用于在给定的材料名称列表中查找对应的材料别名如果找到匹配的材料名称，
     * 则返回其别名；如果没有找到匹配项，则返回空字符串
     *
     * @param material 材料名称，用于查找别名
     * @return 如果找到匹配的材料名称，则返回其别名；否则返回空字符串
     */
    private String getMaterialAlias(String material) {
        // 遍历配置中的所有材料项
        for (MaterialItem item : config.getMaterials()) {
            // 检查当前材料项的名称是否与给定的材料名称相等
            if (item.getMaterial().equals(material)) {
                // 如果找到匹配项，返回该材料项的别名
                return item.getMaterialAlias();
            }
        }
        // 如果没有找到匹配项，返回空字符串
        return "";
    }


    /* ================================大屏相关统计=====================================*/


    /**
     * 统计钢板库存总量
     *
     * @return
     */
    @Override
    public CommonResult<List<PlateMonthStatisticsVO>> monthStoreStatistics() {
        List<PlateMonthStatisticsVO> result = new ArrayList<>(6);
        // 获取当前月的最后一天作为结束日期
        Calendar calendar = Calendar.getInstance();
        SimpleDateFormat formatter = new SimpleDateFormat("MM月");
        // 从当前月开始，向前推算包括当前月在内的最近六个月的统计信息
        for (int i = 5; i >= 0; i--) {
            // 设置为当前日期前 i 个月
            calendar.add(Calendar.MONTH, -i);
            Date monthStart = calendar.getTime();
            Date starDate=DateUtils.getMonthStartDate(monthStart);
            Date monthEnd = DateUtils.getMonthEndDate(monthStart);
            String month = formatter.format(monthStart);
            PlateMonthStatisticsVO stored = zlSteelPlateMapper.storeStatistics(starDate, monthEnd);
            if (stored == null) {
                stored = new PlateMonthStatisticsVO();
            }
            stored.setMonth(month);
            result.add(stored);
            // 恢复到当前日期
            calendar.add(Calendar.MONTH, i);
        }
        return CommonResult.success(result);
    }
}
